package com.zodiac.alioth.common.api.register;


import com.zodiac.alioth.common.api.ApiHandler;
import com.zodiac.alioth.common.api.ApiRequestKey;
import com.zodiac.alioth.common.api.ApiServiceFactory;
import com.zodiac.alioth.common.api.annotation.ApiMapping;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.lang.reflect.Method;

/**
 * Created by well on 2014/7/29.
 */
@Component
public class ApiSpringRegisterProcessor extends InstantiationAwareBeanPostProcessorAdapter implements ApplicationContextAware {

    private final static Logger logger = LoggerFactory.getLogger(ApiSpringRegisterProcessor.class);

    @Resource
    private ApiServiceFactory apiServiceFactory;

    private ApplicationContext applicationContext;

    @Override
    public boolean postProcessAfterInstantiation(final Object bean, final String beanName) throws BeansException {
        ReflectionUtils.doWithMethods(bean.getClass(),new ReflectionUtils.MethodCallback(){

            @Override
            public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
                ApiMapping annotation = method.getAnnotation(ApiMapping.class);
                if(annotation!=null){
                    String apiName = annotation.apiName();
                    String apiVersion = annotation.apiVersion();
                    if(!StringUtils.hasText(apiName)||!StringUtils.hasText(apiVersion)){
                        throw new RuntimeException("apiName or apiVersion cannot null.bean class:" + bean.getClass());
                    }
                    ApiRequestKey apiRequestKey = new ApiRequestKey();
                    apiRequestKey.setApiVersion(apiVersion);
                    apiRequestKey.setApiName(apiName);
                    if(apiServiceFactory.getService(apiRequestKey) != null){
                        logger.error("register api service error duplicate service:apiName" + apiRequestKey.getApiName() + ",apiVersion:" + apiRequestKey.getApiVersion());
                        throw new RuntimeException("register app service error duplicate service:apiName" + apiRequestKey.getApiName() + ",apiVersion:" + apiRequestKey.getApiVersion());
                    }
                    ApiHandler apiHandler = new ApiHandler();
                    apiHandler.setBeanName(beanName);
                    apiHandler.setHandleMethod(method);
                    Object maybeProxyObject = getTheSingletonObject(beanName);
                    apiHandler.setHandlerObject(maybeProxyObject);
                    apiServiceFactory.registerService(apiRequestKey,apiHandler);
                    logger.info("register api service success," + apiRequestKey + ",handle:" + apiHandler);
                }
            }
        });

        return true;
    }


    public void setApiServiceFactory(ApiServiceFactory apiServiceFactory) {
        this.apiServiceFactory = apiServiceFactory;
    }

    private Object getTheSingletonObject(String beanName){
        return applicationContext.getAutowireCapableBeanFactory().getBean(beanName);
    }


    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

}
